//package com.tianji.promotion.service.impl;
//
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.tianji.common.domain.dto.PageDTO;
//import com.tianji.common.exceptions.BadRequestException;
//import com.tianji.common.exceptions.BizIllegalException;
//import com.tianji.common.utils.BeanUtils;
//import com.tianji.common.utils.CollUtils;
//import com.tianji.common.utils.UserContext;
//import com.tianji.promotion.constants.PromotionConstants;
//import com.tianji.promotion.domain.po.Coupon;
//import com.tianji.promotion.domain.po.ExchangeCode;
//import com.tianji.promotion.domain.po.UserCoupon;
//import com.tianji.promotion.domain.query.UserCouponQuery;
//import com.tianji.promotion.domain.vo.CouponVO;
//import com.tianji.promotion.enums.CouponStatus;
//import com.tianji.promotion.enums.ExchangeCodeStatus;
//import com.tianji.promotion.mapper.CouponMapper;
//import com.tianji.promotion.mapper.UserCouponMapper;
//import com.tianji.promotion.service.IExchangeCodeService;
//import com.tianji.promotion.service.IUserCouponService;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.tianji.promotion.utils.CodeUtil;
//import com.tianji.promotion.utils.MyLock;
//import lombok.RequiredArgsConstructor;
//import org.apache.commons.lang3.StringUtils;
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//import org.springframework.aop.framework.AopContext;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.time.LocalDateTime;
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//import java.util.concurrent.TimeUnit;
//import java.util.stream.Collectors;
//
///**
// * <p>
// * 用户领取优惠券的记录，是真正使用的优惠券信息 服务实现类
// * </p>
// *
// * @author mxl
// * @since 2024-07-01
// */
//@Service
//@RequiredArgsConstructor
//public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements IUserCouponService {
//
//    private final CouponMapper couponMapper;
//
//    private final IExchangeCodeService exchangeCodeService;
//
//    private final RedissonClient redissonClient;
//
//    @Override
//    public void receiveCoupon(Long id) {
//        // 1. 根据id查询优惠券信息， 做相关校验
//        if(id == null){
//            throw new BadRequestException("非法参数");
//        }
//        Coupon coupon = couponMapper.selectById(id);
//        if(coupon == null){
//            throw new BadRequestException("优惠券不存在");
//        }
//        if(coupon.getStatus() != CouponStatus.ISSUING){
//            throw new BadRequestException("该优惠状态不是正在发放");
//        }
//        LocalDateTime now = LocalDateTime.now();
//        if(now.isBefore(coupon.getIssueBeginTime()) || now.isAfter(coupon.getIssueEndTime())){
//            throw new BadRequestException("该优惠券不在发放时间");
//        }
//        // 获取当前用户 对该优惠券 已领数量 user coupon 条件userid couponid 统计数量
//        coupon.getUserLimit();
//        Long userId = UserContext.getUser();
//        // 通过redis 实现分布式锁
//        String key = PromotionConstants.REDISLOCK + userId;
//        IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
//        userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon, null);
//
//    }
//
//    @Override
//    public void exchangeCode(String code) {
//        // 1. 校验参数
//        if(StringUtils.isBlank(code)){
//            throw new BadRequestException("非法参数");
//        }
//
//        // 2. 解析兑换码得到id
//        long serialId = CodeUtil.parseCode(code);
//
//        // 3. 判断兑换码是否已经兑换 bitMap
//        boolean result = exchangeCodeService.updateExchangeCodeMark(serialId, true);
//        if(!result){
//            throw new BizIllegalException("兑换码已经被使用");
//        }
//
//        try{
//            // 4. 判断兑换码是否存在
//            ExchangeCode exchangeCode = exchangeCodeService.getById(serialId);
//            if(exchangeCode == null){
//                throw new BadRequestException("兑换码不存在");
//            }
//            // 5. 判断是否过期
//            LocalDateTime now = LocalDateTime.now();
//            LocalDateTime expireTime = exchangeCode.getExpiredTime();
//            if(!now.isAfter(expireTime)){
//                throw new BadRequestException("兑换码已过期");
//            }
//            // 校验并创建用户券
//            Long user = UserContext.getUser();
//            // 查看优惠卷信息
//            Coupon coupon = couponMapper.selectById(exchangeCode.getExchangeTargetId());
//            if(coupon == null){
//                throw new BizIllegalException("优惠券不存在");
//            }
//            // 校验优惠券状态，并生成用户优惠券，更新兑换码状态
//            // 通过redis 实现分布式锁
//            String key = PromotionConstants.REDISLOCK + user;
//            IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
//            userCouponServiceProxy.checkAndCreateUserCoupon(user, coupon, serialId);
//        }catch (Exception e){
//            // 兑换码状态重置
//            exchangeCodeService.updateExchangeCodeMark(serialId, false);
//            throw e;
//        }
//    }
//
//    @Transactional
//    @Override
//    @MyLock(name=PromotionConstants.REDISLOCK+"#{user}")
//    public void checkAndCreateUserCoupon(Long user, Coupon coupon, Long serialNum) {
//        // 获取当前用户 对该优惠券 已领数量 user coupon 条件userid couponid 统计数量
//        // 强制从常量池中取值 保证同一个用户不能超领
//        if(coupon.getTotalNum() <= 0 || coupon.getIssueNum() >= coupon.getTotalNum()){
//            throw new BadRequestException("该优惠券库存不足");
//        }
//        Integer count = this.lambdaQuery()
//                .eq(UserCoupon::getUserId, user)
//                .eq(UserCoupon::getCouponId, coupon.getId())
//                .count();
//        if(count != null && count >= coupon.getUserLimit()){
//            throw new BadRequestException("已达到领取上限");
//        }
//        // 2. 优惠券的已发放数量+1
//        int r = couponMapper.incrIssueNum(coupon.getId());
//        if(r == 0){
//            throw new BizIllegalException("优惠券库存不足");
//        }
//
//        // 3. 生成用户卷
//        saveUserCoupon(user, coupon);
//
//        // 4. 更新兑换码兑换状态
//        if(serialNum != null){
//            // 修改兑换码状态
//            exchangeCodeService.lambdaUpdate()
//                    .set(ExchangeCode::getStatus, ExchangeCodeStatus.USED)
//                    .set(ExchangeCode::getUserId, user)
//                    .eq(ExchangeCode::getId, serialNum)
//                    .eq(ExchangeCode::getStatus, ExchangeCodeStatus.UNUSED)
//                    .update();
//        }
//    }
//
//    @Override
//    public PageDTO<CouponVO> queryMyCoupon(UserCouponQuery query) {
//        // 1. 参数校验
//        if(query == null){
//            throw new BadRequestException("参数不能为空");
//        }
//        // 2. 查询DB
//        Long user = UserContext.getUser();
//        Page<UserCoupon> page = lambdaQuery()
//                .eq(query.getStatus() != null, UserCoupon::getStatus, query.getStatus())
//                .eq(UserCoupon::getUserId, user)
//                .page(query.toMpPageDefaultSortByCreateTimeDesc());
//
//        List<UserCoupon> records = page.getRecords();
//        if(CollUtils.isEmpty(records)){
//            return PageDTO.empty(page);
//        }
//        // 3. 封装数据
//        // 3.1 查询优惠券信息
//        Set<Long> couponIds = records.stream().map(record -> record.getCouponId()).collect(Collectors.toSet());
//        if(CollUtils.isEmpty(couponIds)){
//            return PageDTO.empty(page);
//        }
//        List<Coupon> couponList = couponMapper.selectBatchIds(couponIds);
//        // 3.2 po 转 vo
//        Map<Long, CouponVO> couponVOMap = couponList.stream()
//                .map(coupon -> BeanUtils.copyBean(coupon, CouponVO.class))
//                .collect(Collectors.toMap(CouponVO::getId, c -> c));
//
//        List<CouponVO> couponVOS = records.stream()
//                .filter(record -> couponVOMap.get(record.getCouponId())!=null)
//                .map(record -> couponVOMap.get(record.getCouponId()))
//                .collect(Collectors.toList());
//
//        return PageDTO.of(page, couponVOS);
//    }
//
//    // 保存用户卷
//    private void saveUserCoupon(Long userId, Coupon coupon) {
//        UserCoupon userCoupon = new UserCoupon();
//        userCoupon.setUserId(userId).setCouponId(coupon.getId());
//        LocalDateTime now = LocalDateTime.now();
//        LocalDateTime termEndTime = coupon.getTermEndTime();
//        LocalDateTime termBeginTime = coupon.getTermBeginTime();
//        if(termBeginTime == null && termEndTime == null){
//            termBeginTime = LocalDateTime.now();
//            termEndTime = termBeginTime.plusDays(coupon.getTermDays());
//        }
//        userCoupon.setTermBeginTime(termBeginTime);
//        userCoupon.setTermEndTime(termEndTime);
//        this.save(userCoupon);
//    }
//}
